﻿using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using XFControls.Utils;
using XFControls.XFPanels.XFPanelItems;
using System.Threading;

namespace XFControls.XFPanels
{
    public partial class XFPanelMenuList : XFPanelBase
    {
        protected List<IXFItem> _items;
        private Bitmap _background;
        private Bitmap _mask;
        private bool _backgroundRendered;
        private int _itemHeight;
        private Rectangle _menuBox;
        private XFPanelBase _former;
        private bool _save;
        private List<MenuItem> _contextMenu;

        public XFPanelMenuList(XFPanelBase former)
        {
            _contextMenu = new List<MenuItem>();
            _backgroundRendered = false;
            _background = former.SaveScreen();
            _former = former;
            _save = _former.SavePanelAfterSlide;
            _former.SavePanelAfterSlide = true;
            InitializeComponent();
            _items = new List<IXFItem>();

            Width = Screen.PrimaryScreen.WorkingArea.Width;
        }

        public override void Reset()
        {
            int height = 0;
            foreach (var itm in _items)
            {
                itm.Invalidate();
                itm.ResetHeight();
                height += itm.GetHeight();
            }
            setHeight(height);
            base.Reset();
        }

        public void Resize()
        {
            int height = 0;
            foreach (var itm in _items)
            {
                height += itm.GetHeight();
            }
            setHeight(height);
        }

        public int this[IXFItem itm]
        {
            get { return _items.IndexOf(itm); }
        }

        public IXFItem this[int itm]
        {
            get { return _items[itm]; }
        }

        public void ClearItem(int item)
        {
            if (item >= _items.Count)
                return;

            var itm = _items[item];
            _items.RemoveAt(item);

            itm.Dispose();
            Reset();
        }

        public void ClearItems()
        {
            foreach (var itm in _items)
                itm.Dispose();
            _items.Clear();
            Reset();
        }

        public void ClearItems(int start)
        {
            if (start >= _items.Count)
                return;

            for (int i = start; i < _items.Count; i++)
            {
                _items[i].Dispose();
            }
            _items.RemoveRange(start, _items.Count - start);
            Reset();
        }

        public void ClearItems(int start, int count)
        {
            for (int i = start; i < start + count; i++)
            {
                _items[i].Dispose();
            }
            _items.RemoveRange(start, count);
            Reset();
        }

        public void ClearItemsAfterWaiting(XFItemLoading loading)
        {
            ClearItems(this[loading]);
        }

        public void Add(IXFItem item)
        {
            Add(item, _items.Count + 1);
        }

        public void Add(IXFItem item, int index)
        {
            if (item is XFItemBack)
                HasBack = true;

            if (item.State != XFItemState.Normal)
                item.State = XFItemState.Normal;

            int height = 0;

            if (item.Parent == null)
                item.Parent = this;

            if (index > _items.Count)
                _items.Add(item);
            else
                _items.Insert(index, item);
            foreach (var itm in _items)
            {
                height += itm.GetHeight();
            }
            setHeight(height);
        }

        public void Add(string item)
        {
            if (!string.IsNullOrEmpty(item))
                Add(new XFItemSimpleText(item) { Parent = this });
        }

        public override void PanelPaint(Graphics g)
        {
            if (!_backgroundRendered)
            {
                paintBackground();
            }

            int curY = LocationY + _menuBox.Y;
            bool rendered = false;

            g.DrawImage(_background, 0, 0);
            for (int i = 0; i < _items.Count; i++)
            {
                int curHeight = _items[i].GetHeight();

                if (curHeight == 0)
                    continue;

                if ((curY + curHeight) >= 0 && curY <= Screen.PrimaryScreen.WorkingArea.Height)
                {
                    rendered = true;

                    renderItemBuffer(_items[i]);
                    g.DrawImage(_items[i].Buffer, _menuBox.X, curY);
                }
                else if (rendered) break;

                curY += curHeight;
            }
            XFControlUtils.DrawAlphaColor(g, _mask, Color.White, new Rectangle(_menuBox.X, 0, _mask.Width, _mask.Height), new Rectangle(0, 0, _mask.Width, _mask.Height));
        }

        private void paintBackground()
        {
            if (Parent is XFPanelContainer && Parent.Parent is Form)
            {
                var parent = Parent.Parent as Form;

                foreach (MenuItem item in parent.Menu.MenuItems)
                {
                    _contextMenu.Add(item);
                }
                parent.Menu.MenuItems.Clear();

                var close = new MenuItem()
                {
                    Text = "Close"
                };

                close.Click += (o, e) =>
                {
                    closeMenu();
                };

                parent.Menu.MenuItems.Add(new MenuItem());
                parent.Menu.MenuItems.Add(close);
            }
            using (Graphics gx = Graphics.FromImage(_background))
            {
                int fullScreen = Parent != null ? Parent.Height : Screen.PrimaryScreen.WorkingArea.Height;
                XFControlUtils.DrawBlackout(gx, new Rectangle(0, 0, Width, visibleHeight));
                var rec = this.GetImageRec("menu");
                int width = Parent == null ? Screen.PrimaryScreen.WorkingArea.Width : Parent.Width;
                int localX = (width / 2) - (rec.Width / 2);
                int localY = fullScreen - (_itemHeight > rec.Height ? rec.Height : _itemHeight);

                _menuBox = new Rectangle(localX, localY, rec.Width, rec.Height);

                this.DrawUIAlphaChannel("menu", gx, _menuBox);

                if (_itemHeight > rec.Height)
                    _offsetHeight = Parent.Height - _menuBox.Y;
            }

            _mask = XFControlUtils.CopyRegion(_background, new Rectangle(_menuBox.X, 0, _menuBox.Width, _menuBox.Y + 20));
            _backgroundRendered = true;
        }

        private void renderItemBuffer(IXFItem item)
        {
            if (item.Buffer == null)
            {
                int h = item.GetHeight();
                if (h > 0)
                    item.Buffer = new Bitmap(_menuBox.Width, h);
                using (Graphics gr = Graphics.FromImage(item.Buffer))
                {
                    gr.Clear(BackColor);
                    item.ItemPaint(gr, 0, 0);
                }
            }
        }

        public void MoveToItem(IXFItem item)
        {
            if (_items.Contains(item))
            {
                var itm = _items.IndexOf(item);
                int curY = 0;

                for (int i = 0; i < itm; i++)
                {
                    curY += _items[i].GetHeight();
                }
                LocationY = -curY;

                Invalidate();
            }
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (!_menuBox.Contains(new Point(e.X, e.Y)))
            {
                closeMenu();
                return;
            }

            base.OnMouseDown(e);

            switch (_curState)
            {
                case States.Click:
                    selectItem(e.X, e.Y);
                    getSelectedItem().OnMouseDown(e.X, e.Y);
                    Invalidate();
                    break;
            }
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            switch (_curState)
            {
                case States.Click:
                    var itm = getSelectedItem();
                    if (itm == null)
                    {
                        _curState = States.Idle;
                        return;
                    }

                    itm.OnMouseUp();

                    switch (itm.GetClickResult())
                    {
                        case XFItemClickResult.Nothing:
                            _curState = States.Idle;
                            break;
                        case XFItemClickResult.SlideLeft:
                            _curState = States.SlideLeft;
                            break;
                        case XFItemClickResult.SlideRight:
                            _curState = States.SlideRight;
                            break;
                        case XFItemClickResult.CustomModal:
                            _curState = States.Modal;
                            break;
                    }

                    closeMenu();
                    deselectItem();
                    break;
            }

            base.OnMouseUp(e);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            switch (_curState)
            {
                case States.Scroll:
                    deselectItem();
                    Invalidate();
                    break;
                case States.Swipe:
                    if ((Attributes & PanelAttributes.Swipe) != PanelAttributes.Swipe)
                    {
                        deselectItem();
                        Invalidate();
                    }
                    else
                    {
                        var itm = getSelectedItem();
                        itm.OnMouseMove(e.X, e.Y);
                    }
                    break;
            }
        }

        private void deselectItem()
        {
            foreach (var itm in _items)
            {
                if (itm.ItemType == XFItemType.Display)
                    continue;

                if (itm.State == XFItemState.Selected && itm.ItemType != XFItemType.ClickableNonChange)
                {
                    itm.Invalidate();
                }
                itm.State = XFItemState.Normal;
            }

            if ((Attributes & PanelAttributes.Swipe) == PanelAttributes.Swipe)
                Attributes = Attributes ^ PanelAttributes.Swipe;
        }

        private void closeMenu()
        {
            try
            {
                var test = Parent != null && !Parent.IsDisposed;
            }
            catch (ObjectDisposedException) { return; }

            if (Parent is XFPanelContainer)
            {
                if (Parent.Parent is Form)
                {
                    var parent = Parent.Parent as Form;
                    parent.Menu.MenuItems.Clear();

                    foreach (MenuItem item in _contextMenu)
                    {
                        parent.Menu.MenuItems.Add(item);
                    }
                }

                var par = Parent as XFPanelContainer;
                _former.SavePanelAfterSlide = _save;
                par.SetMainPanel(_former);
            }
        }

        private void selectItem(int x, int y)
        {
            int curY = LocationY + _menuBox.Y;

            for (int i = 0; i < _items.Count; i++)
            {
                int curHeight = _items[i].GetHeight();

                if (y > curY && y < curY + curHeight)
                {
                    if (_items[i].ItemType == XFItemType.Display)
                        return;
                    else if (_items[i].ItemType == XFItemType.Swipable)
                        Attributes |= PanelAttributes.Swipe;

                    if (_items[i].ItemType != XFItemType.ClickableNonChange)
                    {
                        _items[i].Invalidate();
                    }
                    _items[i].State = XFItemState.Selected;
                    return;
                }
                curY += curHeight;
            }
        }

        private IXFItem getSelectedItem()
        {
            foreach (var itm in _items)
            {
                if (itm.State == XFItemState.Selected)
                    return itm;
            }
            return null;
        }

        private void setHeight(int height)
        {
            _itemHeight = height;
            int fullScreen = Parent != null ? Parent.Height : Screen.PrimaryScreen.WorkingArea.Height;
            if (height < fullScreen)
                height = fullScreen;

            Height = height;
        }

        protected override void Dispose()
        {
            ClearItems();
            base.Dispose();
        }
    }
}
